    /* chimaera_user-table.c : working with the `chimaera_user' table
 *
 * ====================================================================
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */

#include "bdb_compat.h"
#include "svn_fs.h"
#include "svn_pools.h"
#include "../fs.h"
#include "../err.h"
#include "../util/skel.h"
#include "../util/fs_skels.h"
#include "../../libsvn_fs/fs-loader.h"
#include "bdb-err.h"
#include "dbt.h"
#include "rev-table.h"
#include "../trail.h"

#include "svn_private_config.h"
#include "private/svn_fs_util.h"

#include "chimaera_user-table.h"


/* Opening/creating the `chimaera_user' table.  */

int svn_fs_bdb__open_chimaera_user_table(DB **chimaerauser_p,
                                     DB_ENV *env,
                                     svn_boolean_t create)
{
  const u_int32_t open_flags = (create ? (DB_CREATE | DB_EXCL) : 0);
  DB *chimaera_user;

  BDB_ERR(svn_fs_bdb__check_version());
  BDB_ERR(db_create(&chimaera_user, env, 0));
  BDB_ERR((chimaera_user->open)(SVN_BDB_OPEN_PARAMS(chimaera_user, NULL),
								"chimaera_user", 0, DB_RECNO,
								open_flags, 0666));

  *chimaerauser_p = chimaera_user;
  return 0;
}



/* Storing and retrieving filesystem revisions.  */


svn_error_t *
svn_fs_bdb__get_chimaera_user(chimaerauser_t **chimaerauser_p,svn_revnum_t id,
							  svn_fs_t *fs, apr_pool_t *pool)
{
  base_fs_data_t *bfd = fs->fsap_data;
  int db_err;
  DBT key, value;
  skel_t *skel;
  DBC *cursor = 0;
  db_recno_t recno = id;

  
  /* rev >= 0 or get the last record */
  if (SVN_IS_VALID_REVNUM(id))
  {
	 db_err = bfd->chimaera_user->get(bfd->chimaera_user, NULL,
	  svn_fs_base__set_dbt(&key, &recno,
	  sizeof(recno)),
	  svn_fs_base__result_dbt(&value),
	  0);


  }else{
	  SVN_ERR(BDB_WRAP(fs, "getting youngest revision (creating cursor)",
		  bfd->chimaera_user->cursor(bfd->chimaera_user, NULL,
		  &cursor, 0)));

	  /* Find the last entry in the `revisions' table.  */
	  db_err = svn_bdb_dbc_get(cursor,
		  svn_fs_base__recno_dbt(&key, &recno),
		  svn_fs_base__result_dbt(&value),
		  DB_LAST);
  }
  
  svn_fs_base__track_dbt(&value, pool);

  /* If there's no such node, return an appropriately specific error.  */
  if (db_err == DB_NOTFOUND)
	  return svn_error_createf
	  (SVN_ERR_FS_NO_SUCH_REPRESENTATION, 0,
	  _("No such chimaerauser '%s'"), key);

  /* Parse the chimaerauser skel.  */
  skel = svn_fs_base__parse_skel(value.data, value.size, pool);

  /* Convert to a native type.  */
  SVN_ERR(svn_fs_base__parse_chimaerauser_skel(chimaerauser_p, skel, pool));

  /* You can't commit a transaction with open cursors, because:
  1) key/value pairs don't get deleted until the cursors referring
  to them are closed, so closing a cursor can fail for various
  reasons, and txn_commit shouldn't fail that way, and
  2) using a cursor after committing its transaction can cause
  undetectable database corruption.  */
  if (cursor)
  {
	  SVN_ERR(BDB_WRAP(fs, "getting youngest revision (closing cursor)",
		  svn_bdb_dbc_close(cursor)));
  }


  return SVN_NO_ERROR;
}

//use cursor and find the record whose userid equals @a user_ID
svn_error_t *
svn_fs_bdb__get_chimaera_user_by_userid(chimaerauser_t **chimaerauser_p,svn_string_t *user_ID,
							  svn_revnum_t *id,svn_fs_t *fs,apr_pool_t *pool)
{
	base_fs_data_t *bfd = fs->fsap_data;
	int db_err;
	DBT key, value;
	skel_t *skel;
	DBC *cursor = 0;
	db_recno_t recno = *id;
	apr_pool_t *subpool;

	SVN_ERR(BDB_WRAP(fs, "getting youngest revision (creating cursor)",
			bfd->chimaera_user->cursor(bfd->chimaera_user, NULL,
			&cursor, 0)));

	/* 
		the apr advises that when doing unbounded iteration
		better using sub_pool
	*/
	subpool = svn_pool_create(pool);

	while ((db_err = svn_bdb_dbc_get(cursor,
		svn_fs_base__recno_dbt(&key, &recno),
		svn_fs_base__result_dbt(&value),DB_NEXT))==0)
	{
		apr_pool_clear(subpool);
		/* Parse the chimaerauser skel.  */
		skel = svn_fs_base__parse_skel(value.data, value.size, subpool);

		/* Convert to a native type.  */
		SVN_ERR(svn_fs_base__parse_chimaerauser_skel(chimaerauser_p, skel, subpool));

		if (!memcmp((*chimaerauser_p)->userid->data,user_ID->data,user_ID->len)
			&&((*chimaerauser_p)->userid->len == user_ID->len))
		{
			SVN_ERR(svn_fs_base__parse_chimaerauser_skel(chimaerauser_p, skel, pool));
			*id = recno;
			break;
		}
	}

	apr_pool_destroy(subpool);

	if (cursor)
	{
		SVN_ERR(BDB_WRAP(fs, "getting user by userid (closing cursor)",
			svn_bdb_dbc_close(cursor)));
	}
	
	/* If not found the user with the user_ID, return an error.  */
	if (db_err == DB_NOTFOUND)
		return svn_error_createf
		(SVN_ERR_FS_NO_SUCH_REPRESENTATION, 0,
		_("No such chimaerauser '%s'"), key);
	else{
		return SVN_NO_ERROR;	
	}
		
}

//use cursor and find the record whose privilege equals @a privilege
svn_error_t *
svn_fs_bdb__get_chimaera_user_by_privilege(chimaerauser_t **chimaerauser_p,svn_string_t *user_ID,
										svn_revnum_t *id,svn_fs_t *fs,apr_pool_t *pool)
{
	
	return SVN_NO_ERROR;	

}


/* Write REVISION to FS as part of TRAIL.  If *REV is a valid revision
   number, write this revision as one that corresponds to *REV, else
   write a new revision and return its newly created revision number
   in *REV.  */
svn_error_t *
svn_fs_bdb__put_chimaera_user(chimaerauser_t *chimaerauser_p,svn_revnum_t *rev,
							  svn_fs_t *fs, DB_TXN *txn,apr_pool_t *pool)
{
  base_fs_data_t *bfd = fs->fsap_data;
  int db_err;
  db_recno_t recno = 0;
  skel_t *skel;
  DBT key, value;

  /* Convert from native type to skel. */
  SVN_ERR(svn_fs_base__unparse_chimaerauser_skel(&skel, chimaerauser_p, pool));

  if (SVN_IS_VALID_REVNUM(*rev))
    {
      DBT query, result;

      /* Update the filesystem revision with the new skel. */
      recno = *rev;
      //svn_fs_base__trail_debug(trail, "revisions", "put");
      db_err = bfd->chimaera_user->put
        (bfd->chimaera_user, txn,
         svn_fs_base__set_dbt(&query, &recno, sizeof(recno)),
         svn_fs_base__skel_to_dbt(&result, skel, pool), 0);
      return BDB_WRAP(fs, "updating filesystem revision", db_err);
    }

  //svn_fs_base__trail_debug(trail, "revisions", "put");

  db_err = bfd->chimaera_user->put(bfd->chimaera_user, txn,
                               svn_fs_base__recno_dbt(&key, &recno),
                               svn_fs_base__skel_to_dbt(&value, skel, pool),
                               DB_APPEND);
  SVN_ERR(BDB_WRAP(fs, "storing filesystem revision", db_err));

  /* Turn the record number into a Subversion revision number.
     Revisions are numbered starting with zero; Berkeley DB record
     numbers begin with one.  */
  *rev = recno;
  return SVN_NO_ERROR;
}
